package zhh.tangbao.wechat.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import zhh.tangbao.auxiliary.common.CallBackStatus;
import zhh.tangbao.auxiliary.common.ResponseStatus;
import zhh.tangbao.auxiliary.dao.SystemOpinionDao;
import zhh.tangbao.auxiliary.entity.SystemOpinion;
import zhh.tangbao.auxiliary.vo.opinion.OpinionInfoVo;
import zhh.tangbao.commodity.constant.OrderStatus;
import zhh.tangbao.commodity.constant.PickupStatus;
import zhh.tangbao.commodity.constant.SellStatus;
import zhh.tangbao.commodity.dao.*;
import zhh.tangbao.commodity.dto.CommodityMachineStockUpdateDto;
import zhh.tangbao.commodity.entity.*;
import zhh.tangbao.commodity.manager.OrderManager;
import zhh.tangbao.commodity.manager.OrderPickUpManager;
import zhh.tangbao.commodity.manager.pickup.PickUpOrder;
import zhh.tangbao.commodity.manager.pickup.PickUpOrderContent;
import zhh.tangbao.commodity.pojo.CommodityOrderReceipt;
import zhh.tangbao.commodity.vo.order.WeChatOrderContentVo;
import zhh.tangbao.commodity.vo.stock.CartStockVo;
import zhh.tangbao.syslog.dao.WorkRecordDao;
import zhh.tangbao.syslog.entity.WorkRecord;
import zhh.tangbao.system.constant.DataStatus;
import zhh.tangbao.system.entity.PagerEntity;
import zhh.tangbao.system.exception.ServiceException;
import zhh.tangbao.system.utils.*;
import zhh.tangbao.websocket.WebSocketSendMessageService;
import zhh.tangbao.websocket.WebSocketServiceType;
import zhh.tangbao.websocket.pojo.WebSocketMessageEntity;
import zhh.tangbao.wechat.api.factory.WeChatPayRequestBodyFactory;
import zhh.tangbao.wechat.api.result.detai.WeChatAccessTokenApiResult;
import zhh.tangbao.wechat.api.result.detai.WeChatGetPhoneNumberApiResult;
import zhh.tangbao.wechat.api.result.detai.WeChatLoginApiResult;
import zhh.tangbao.wechat.cache.WeChatCache;
import zhh.tangbao.wechat.dao.WeChatUserDao;
import zhh.tangbao.wechat.dto.WeChatMachineQueryDto;
import zhh.tangbao.wechat.dto.WeChatOrderQueryDto;
import zhh.tangbao.wechat.dto.WeChatUserLoginDto;
import zhh.tangbao.wechat.dto.WeChatUserQueryDto;
import zhh.tangbao.wechat.dto.commodity.CommodityQueryDto;
import zhh.tangbao.wechat.dto.opinion.UserOpinionQueryDto;
import zhh.tangbao.wechat.dto.replenishment.ReplenishmentMachineStockQueryDto;
import zhh.tangbao.wechat.dto.replenishment.ReplenishmentStockDataDto;
import zhh.tangbao.wechat.dto.worker.WorkerRecordQueryDto;
import zhh.tangbao.wechat.entity.WeChatUser;
import zhh.tangbao.wechat.pojo.CartItem;
import zhh.tangbao.wechat.service.WeChatService;
import zhh.tangbao.wechat.vo.*;
import zhh.tangbao.wechat.vo.cart.CartItemVo;
import zhh.tangbao.wechat.vo.commodity.CommodityPageInMachineVo;
import zhh.tangbao.wechat.vo.opinion.UserOpinionListItemVo;
import zhh.tangbao.wechat.vo.order.OrderContentDetailDaoVo;
import zhh.tangbao.wechat.vo.order.OrderContentDetailVo;
import zhh.tangbao.wechat.vo.order.OrderDetailVo;
import zhh.tangbao.wechat.vo.order.OrderMachineDetailVo;
import zhh.tangbao.wechat.vo.replenishment.ReplenishmentMachineStockVo;
import zhh.tangbao.wechat.vo.worker.WorkerPanel;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 2023/2/27
 *
 * @author 粥灰灰
 * @version 1.0
 * 涉及微信平台的服务
 */

@Slf4j
@Service
public class WeChatServiceImpl implements WeChatService {

    @Value("${wx.appId}")
    private String appId;
    @Value("${wx.appSecret}")
    private String appSecret;

    /**
     * 支付接口调用地址
     */
    @Value("${wx.payUrl}")
    private String payUrl;

    @Value("${wx.mchKey}")
    private String mchKey;

    @Autowired
    private HttpClientUtil httpClientUtil;

    @Autowired
    private WeChatUserDao weChatUserDao;

    @Autowired
    private WeChatCache weChatCache;

    @Autowired
    private WeChatUserHolderUtil weChatUserHolderUtil;

    @Autowired
    private CommodityOrderDao orderDao;

    @Autowired
    private CommodityMachineEntityDao machineDao;

    @Autowired
    private CommodityMachineHistoryDao historyDao;

    @Autowired
    private WeChatPayRequestBodyFactory weChatPayRequestBodyFactory;

    @Autowired
    private CommodityOrderContentDao orderContentDao;

    @Autowired
    private EncryptUtil encryptUtil;

    @Autowired
    private OrderManager orderTimerManager;

    @Autowired
    private OrderPickUpManager pickUpManager;

    @Autowired
    private CommodityMachineStockDao stockDao;

    @Autowired
    private CommodityMachineStockDataDao stockDataDao;

    @Value("${wx.imgAccessPathPrefix}")
    private String imgAccessPathPrefix;

    @Autowired
    private WorkRecordDao workDao;

    @Autowired
    private SystemOpinionDao opinionDao;

    @Autowired
    private WebSocketSendMessageService messageService;

    @Override
    public WeChatLoginVo login(WeChatUserLoginDto dto) {
        try {
            Assert.notBlank(dto.getJsCode(), "js_code不能为空");
            String url = new StringBuilder()
                    .append("https://api.weixin.qq.com/sns/jscode2session?appid=").append(appId)
                    .append("&secret=").append(appSecret)
                    .append("&js_code=").append(dto.getJsCode())
                    .append("&grant_type=authorization_code").toString();
            WeChatLoginApiResult r = httpClientUtil.doGet(url, WeChatLoginApiResult.class);
            Assert.notNull(r, "登录失败");
            Assert.isFalse(r.isError(), r.getErrorDetailMsg());
            String openid = r.getOpenid();
            WeChatUser wechatUser = weChatUserDao.selectOne(new QueryWrapper<WeChatUser>().eq("open_id", openid));
            Date now = new Date();
            String token = ZhhStringUtil.normalGenerate();
            if (null == wechatUser) {
                // 从未登录过小程序
                // 进行注册操作并发放token
                wechatUser = new WeChatUser();
                wechatUser
                        .setOpenId(openid)
                        .setLastLogin(now)
                        .setRecordTime(now)
                        .setPhoneNumber(dto.getPhoneNumber())
                        .setToken(token)
                        .setIsReplenishment(0);
                weChatUserDao.insert(wechatUser);
            } else {
                // 之前登录过小程序
                // 更新最近登录时间
                // 生成新的token
                wechatUser
                        .setLastLogin(now)
                        .setToken(token);
                weChatUserDao.updateById(wechatUser);
            }
            weChatCache.login(new WeChatUserCacheVo(wechatUser));
            WeChatLoginVo result = new WeChatLoginVo();
            result.setReplenishment(wechatUser.getIsReplenishment() == 1)
                    .setToken(token);
            return result;
        } catch (Exception e) {
            log.error("[login]msg: {}", e.getMessage());
            throw new ServiceException("服务器异常，请稍后重试");
        }
    }

    @Override
    public void logout() {
        WeChatUserCacheVo user = weChatUserHolderUtil.getCurrentUser();
        weChatCache.logout(user.getToken());
        WeChatUser weChatUser = weChatUserDao.selectById(user.getId());
        if (null != weChatUser) {
            // 用户退出登录的话需要清空token，token被清空后就无法根据token查询用户，那么在快速登录时会被视为未登录以达到目的
            weChatUser.setToken("");
            weChatUserDao.updateById(weChatUser);
        }
    }

    @Override
    public WeChatUser getWeChatUserByToken(String token) {
        return weChatUserDao.selectOne(new QueryWrapper<WeChatUser>().eq("token", token));
    }

    @Override
    public boolean updateIfNotExpire(WeChatUser weChatUser) {
        if (null == weChatUser) {
            return false;
        }
        Date lastLogin = weChatUser.getLastLogin();
        // 防护策略，如果没有上次登录时间则直接视作从未登录，也就是token过期，需要重新授权登录
        if (null == lastLogin) {
            return true;
        }
        // 如果存在则对比是否超过一定时间
        Date now = new Date();
        long duringTime = now.getTime() - lastLogin.getTime();
        // 设定为间隔30天没登陆则算过期
        long duringNum = 2592000000L;
        if (duringTime > duringNum) {
            return true;
        }
        // 如果都没过期则更新最后登录时间
        weChatUser.setLastLogin(now);
        weChatUserDao.updateById(weChatUser);
        return false;
    }

    @Override
    public List<WeChatCommodityMachineVo> machinePage(WeChatMachineQueryDto dto) {
        List<WeChatCommodityMachineVo> vo = machineDao.wechatMachinePage(dto);
        if (CollUtil.isEmpty(vo)) {
            return vo;
        }
        for (int i = 0; i < vo.size(); i++) {
            WeChatCommodityMachineVo v = vo.get(i);
            if (StrUtil.isNotBlank(v.getMachineImg())) {
                v.setMachineImg(this.imgAccessPathPrefix + v.getMachineImg());
            }
        }
        return vo;
    }

    @Override
    public Integer machineCount(WeChatMachineQueryDto dto) {
        QueryWrapper<CommodityMachineEntity> query = new QueryWrapper<CommodityMachineEntity>()
                .eq("data_status", DataStatus.ENABLE);
        if (StrUtil.isNotBlank(dto.getPosition())) {
            query.like("machine_position", dto.getPosition());
        }
        return machineDao.selectCount(query);
    }


    @Override
    public List<WeChatCommodityOrderVo> wechatPage(WeChatOrderQueryDto dto) {
        // 需要用到微信小程序用户ID来查找有关他的订单信息
        String userId = weChatUserHolderUtil.getCurrentUser().getId();
        dto.setUserId(userId);
        // 微信小程序端通过上拉懒加载的方式加载订单数据，因此暂时不用订单总个数
        List<WeChatCommodityOrderVo> vos = orderDao.wechatPage(dto);
        if (CollUtil.isEmpty(vos)) {
            return vos;
        }
        Map<String, WeChatCommodityOrderVo> collect = vos.stream().collect(Collectors.toMap(WeChatCommodityOrderVo::getId, Function.identity()));
        // 获取订单内容
        List<WeChatOrderContentVo> contents = orderContentDao.listWeChatOrderContentVoByOrderIds(collect.keySet());
        if (CollUtil.isEmpty(contents)) {
            return vos;
        }
        for (int i = 0; i < contents.size(); i++) {
            WeChatOrderContentVo v = contents.get(i);
            WeChatCommodityOrderVo vo = collect.get(v.getOrderId());
            if (null == vo) {
                continue;
            }
            if (null == vo.getContent()) {
                vo.setContent(Lists.newArrayList(v));
            } else {
                vo.getContent().add(v);
            }
            if (StrUtil.isNotEmpty(v.getImg())) {
                v.setImg(imgAccessPathPrefix + v.getImg());
            }
        }
        return vos;
    }

    @Override
    public int wechatOrderCount(WeChatOrderQueryDto dto) {
        String userId = weChatUserHolderUtil.getCurrentUser().getId();
        QueryWrapper<CommodityOrder> wrapper = new QueryWrapper<CommodityOrder>()
                .eq("record_user_id", userId).eq("data_status", DataStatus.ENABLE);
        if (null != dto.getOrderStatus()) {
            wrapper.eq("order_status", dto.getOrderStatus());
        }
        return orderDao.selectCount(wrapper);
    }

    @Override
    public int wechatDeleteOrder(String id) {
        CommodityOrder order = orderDao.selectById(id);
        Assert.notNull(order, "该订单记录不存在或已被删除");
        order.setDataStatus(DataStatus.DELETED)
                .setUpdateInfo(weChatUserHolderUtil.getCurrentUser().getId());
        return orderDao.updateById(order);
    }

    @Override
    public List<WeChatCommodityMachineHistoryVo> userMachineHistoryPage(WeChatMachineQueryDto dto) {
        // 根据用户ID查找记录
        dto.setUserId(weChatUserHolderUtil.getCurrentUser().getId());
        List<WeChatCommodityMachineHistoryVo> page = historyDao.page(dto);
        if (CollUtil.isEmpty(page)) {
            return page;
        }
        for (int i = 0; i < page.size(); i++) {
            WeChatCommodityMachineHistoryVo v = page.get(i);
            String img = v.getMachineImg();
            if (StrUtil.isNotEmpty(img)) {
                v.setMachineImg(imgAccessPathPrefix + img);
            }
        }
        return page;
    }

    @Override
    public Integer userMachineHistoryCount(WeChatMachineQueryDto dto) {
        // 根据用户ID查找记录
        dto.setUserId(weChatUserHolderUtil.getCurrentUser().getId());
        return historyDao.count(dto);
    }

    @Override
    public Integer upsertMachineHistory(CommodityMachineHistory history) {
        String id = weChatUserHolderUtil.getCurrentUser().getId();
        history.setRecordUserId(id);
        history.setReadTime(new Date());
        // 有时用户不一定会从浏览记录里进入售货机，当此种情况发生时只能通过机器id和用户id查询记录
        if (null == history.getHistoryId()) {
            CommodityMachineHistory hasHistory = historyDao.selectOne(new QueryWrapper<CommodityMachineHistory>().eq("machine_id", history.getMachineId()).eq("record_user_id", id));
            if (null != hasHistory) {
                history.setHistoryId(hasHistory.getHistoryId());
            }
        }
        return historyDao.upsert(history);
    }

    @Transactional
    @Override
    public Map<String, String> buy(CommodityOrder order) {
        WeChatUserCacheVo currentUser = weChatUserHolderUtil.getCurrentUser();
        order.setCreateUserId(currentUser.getId());
        order.setBaseCreateInfo(currentUser.getId());
        order.setOrderStatus(OrderStatus.SUBMIT_BUT_NOT_PAY.getCode());
        orderDao.insert(order);
        List<CommodityOrderContent> content = order.getContent();
        if (CollUtil.isEmpty(content)) {
            throw new ServiceException("订单内容不能为空");
        }
        List<Integer> stockIds = content.stream().map(CommodityOrderContent::getStockId).collect(Collectors.toList());
        List<CommodityMachineStockData> stockData = stockDataDao.selectList(new QueryWrapper<CommodityMachineStockData>().in("stock_id", stockIds));
        if (CollUtil.isEmpty(stockData)) {
            throw new ServiceException("涉及售货机库存为空");
        }
        List<CommodityMachineStockUpdateDto> cmsud = Lists.newArrayList();
        List<Integer> ids = Lists.newArrayList();
        Map<Integer, CommodityMachineStockData> map = stockData.stream().collect(Collectors.toMap(CommodityMachineStockData::getStockId, Function.identity()));
        for (int i = 0; i < content.size(); i++) {
            CommodityOrderContent oc = content.get(i);
            oc.setCommodityOrderId(order.getId());
            oc.setPickupStatus(PickupStatus.UNPICK);
            Integer sid = oc.getStockId();
            CommodityMachineStockData data = map.get(sid);
            if (null == data) {
                continue;
            }
            if (data.getToBeSold() >= oc.getCommodityEntityCount()) {
                CommodityMachineStockUpdateDto commodityMachineStockUpdateDto = new CommodityMachineStockUpdateDto(sid, -oc.getCommodityEntityCount());
                cmsud.add(commodityMachineStockUpdateDto);
                ids.add(sid);
            } else {
                throw new ServiceException("库存不足，无法添加订单");
            }
        }
        stockDao.reduceStockToBeSoldCount(cmsud, ids);
        orderContentDao.insertBatchSomeColumn(content);
        Map<String, String> wechatPaymentResult = Maps.newHashMap();
        // 返回订单，用于生成取货凭证
        wechatPaymentResult.put("orderId", order.getId());
        // 放入订单计时器
        orderTimerManager.addOrderExpire(order.getId());
        // 因为付款流程还未结束，所以这里只需要返回支付参数+订单号即可
        weChatCache.clearUserCart(currentUser.getId());
        return wechatPaymentResult;
    }

    @Override
    public int orderPayment(String orderId) {
        CommodityOrder update = new CommodityOrder();
        update.setPaymentTime(new Date());
        update.setOrderStatus(OrderStatus.PAY_BUT_NOT_PICKED.getCode());
        QueryWrapper<CommodityOrder> wrapper = new QueryWrapper<CommodityOrder>().eq("id", orderId).eq("data_status", DataStatus.ENABLE);
        int i = orderDao.update(update, wrapper);
        // 放入取货队列
        List<PickUpOrderContent> pickUpOrderContents = orderContentDao.listPickUpOrderContent(orderId, PickupStatus.UNPICK);
        if (CollUtil.isEmpty(pickUpOrderContents)) {
            return i;
        }
        // 按照机器ID分组，并依次放入机器的取货队列中
        Map<String, List<PickUpOrderContent>> collect = pickUpOrderContents.stream().collect(Collectors.groupingBy(PickUpOrderContent::getCommodityMachineId));
        collect.forEach((k, v) -> {
            pickUpManager.addPickUp(k, new PickUpOrder(orderId, v));
        });
        // 订单过期计时
        orderTimerManager.cancelExpireTimer(orderId);
        return i;
    }

    @Override
    public CommodityOrderReceipt getReceipt(String orderId) {
        CommodityOrderReceipt receipt = new CommodityOrderReceipt();
        receipt.setReceipt(encryptUtil.MD5(orderId));
        return receipt;
    }

    @Override
    public int waitCount(String machineId, String orderId) {
        return pickUpManager.waitCount(machineId, orderId);
    }

    @Override
    public int cancelOrder(String orderId) {
        orderTimerManager.cancelExpireTimer(orderId);
        return orderDao.cancelOrderIfNotPayment(orderId, OrderStatus.CANCEL.getCode());
    }

    @Override
    public List<WeChatUserListOptionsVo> userListOptions(String queryString) {
        return weChatUserDao.userListOptionsByPhoneNumber(queryString);
    }

    @Override
    public Page<WeChatUser> page(WeChatUserQueryDto dto) {
        Page<WeChatUser> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        QueryWrapper<WeChatUser> query = new QueryWrapper<>();
        if (null != dto.getIsReplenishment()) {
            query.eq("is_replenishment", dto.getIsReplenishment());
        }
        if (StrUtil.isNotBlank(dto.getPhoneNumber())) {
            query.like("phone_number", dto.getWechatAccount());
        }
        return weChatUserDao.selectPage(page, query);
    }

    @Override
    public int batchDeleteReplenishment(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return 0;
        }
        WeChatUser update = new WeChatUser();
        update.setIsReplenishment(0);
        return weChatUserDao.update(update, new QueryWrapper<WeChatUser>().in("id", ids));
    }

    @Override
    public WeChatUser getWeChatUserById(String id) {
        WeChatUser weChatUser = weChatUserDao.selectById(id);
        Assert.notNull(weChatUser, "该用户不存在");
        return weChatUser;
    }

    @Override
    public PagerEntity<CommodityPageInMachineVo> commodityPageInMachine(PagerEntity<CommodityPageInMachineVo> pager, CommodityQueryDto dto) {
        dto.setSellStatus(SellStatus.TAKE_ON);
        long count = weChatUserDao.commodityPageInMachineCount(pager, dto);
        pager.setTotalNum(count);
        if (count <= 0) {
            pager.setData(Lists.newArrayList());
            return pager;
        }
        List<CommodityPageInMachineVo> commodityPageInMachineVos = weChatUserDao.listCommodityPageInMachineVos(pager, dto);
        for (int i = 0; i < commodityPageInMachineVos.size(); i++) {
            CommodityPageInMachineVo vo = commodityPageInMachineVos.get(i);
            if (StrUtil.isNotBlank(vo.getCommodityImg())) {
                vo.setCommodityImg(imgAccessPathPrefix + vo.getCommodityImg());
            }
        }
        pager.setData(commodityPageInMachineVos);
        return pager;
    }

    @Override
    public String getPhoneNumber(String getPhoneCode) {
        Assert.notBlank(getPhoneCode, "phoneCode不能为空");
        String url = new StringBuilder()
                .append("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential")
                .append("&appid=").append(appId)
                .append("&secret=").append(appSecret).toString();
        WeChatAccessTokenApiResult r = httpClientUtil.doGet(url, WeChatAccessTokenApiResult.class);
        Assert.notNull(r, "获取失败");
        Assert.isFalse(r.isError(), r.getErrorDetailMsg());
        url = new StringBuilder("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=").append(r.getAccess_token())
                .toString();
        Map<String, String> body = Maps.newHashMap();
        body.put("code", getPhoneCode);
        WeChatGetPhoneNumberApiResult gr = httpClientUtil.doPost(url, JSONObject.toJSONString(body), WeChatGetPhoneNumberApiResult.class);
        Assert.isFalse(gr.isError(), gr.getErrorDetailMsg());
        String phone = gr.getPhone_info().getPurePhoneNumber();
        WeChatUserCacheVo currentUser = weChatUserHolderUtil.getCurrentUser();
        weChatUserDao.update(new WeChatUser().setPhoneNumber(phone), new QueryWrapper<WeChatUser>().eq("id", currentUser.getId()));
        return phone;
    }

    @Override
    public List<CartItemVo> userCart() {
        WeChatUserCacheVo currentUser = weChatUserHolderUtil.getCurrentUser();
        String id = currentUser.getId();
        List<CartItem> userCart = weChatCache.getUserCart(id);
        List<CartItemVo> vos = Lists.newArrayList();
        if (userCart.isEmpty()) {
            return vos;
        }
        List<Integer> stockId = userCart.stream().map(CartItem::getStockId).collect(Collectors.toList());
        List<CartStockVo> csv = stockDao.listCartStockVoByStockIds(stockId);
        if (CollUtil.isEmpty(csv)) {
            return vos;
        }
        Map<Integer, CartStockVo> stockVoMap = csv.stream().collect(Collectors.toMap(CartStockVo::getStockId, Function.identity()));
        for (int i = 0; i < userCart.size(); i++) {
            CartItem ci = userCart.get(i);
            CartStockVo cartStockVo = stockVoMap.get(ci.getStockId());
            CartItemVo v = new CartItemVo(ci, cartStockVo);
            if (StrUtil.isNotEmpty(v.getCommodityImg())) {
                v.setCommodityImg(imgAccessPathPrefix + v.getCommodityImg());
            }
            vos.add(v);
        }
        return vos;
    }

    @Override
    public void addUserCart(CartItem item) {
        String id = weChatUserHolderUtil.getCurrentUser().getId();
        List<CartItem> userCart = weChatCache.getUserCart(id);
        if (CollUtil.isEmpty(userCart)) {
            weChatCache.addUserCart(id, item);
            return;
        }
        for (int i = 0; i < userCart.size(); i++) {
            if (userCart.get(i).getStockId().equals(item.getStockId())) {
                return;
            }
        }
        weChatCache.addUserCart(id, item);
    }

    @Override
    public int deleteUserCart(Integer stockIndex, Integer stockId) {
        String id = weChatUserHolderUtil.getCurrentUser().getId();
        return weChatCache.deleteUserCart(id, stockIndex, stockId);
    }

    @Override
    public Map<String, String> requestPayment(String orderId) {
        CommodityOrder order = orderDao.selectById(orderId);
        WeChatUserCacheVo currentUser = weChatUserHolderUtil.getCurrentUser();
        return getWechatPaymentResult(order.getId(), weChatUserDao.getOpenIdByUserId(currentUser.getId()), order.getId(), order.getOrderTotalPrice(), ZhhStringUtil.randomString32());
    }

    @Override
    public OrderDetailVo getWeChatOrderDetail(String id) {
        OrderDetailVo vo = orderDao.getOrderDetailVoById(id);
        List<OrderContentDetailDaoVo> contents = orderContentDao.listOrderContentDetailVoByOrderId(id);
        if (CollUtil.isEmpty(contents)) {
            return vo;
        }
        Map<String, OrderMachineDetailVo> map = Maps.newHashMap();
        for (int i = 0; i < contents.size(); i++) {
            OrderContentDetailDaoVo ocddv = contents.get(i);
            if (StrUtil.isNotEmpty(ocddv.getCommodityImg())) {
                ocddv.setCommodityImg(imgAccessPathPrefix + ocddv.getCommodityImg());
            }
            if (StrUtil.isNotEmpty(ocddv.getMachineImg())) {
                ocddv.setMachineImg(imgAccessPathPrefix + ocddv.getMachineImg());
            }
            OrderMachineDetailVo omdv = map.computeIfAbsent(ocddv.getMachineId(), key -> new OrderMachineDetailVo(ocddv));
            omdv.getContents().add(new OrderContentDetailVo(ocddv));
            if (PickupStatus.PICKED == ocddv.getPickupStatus()) {
                omdv.setTake(PickupStatus.PICKED);
            }
        }
        vo.setContent(Lists.newArrayList(map.values()));
        Long expireTime = orderTimerManager.getExpireTime(id);
        if (expireTime > 0) {
            vo.setExpireTime(expireTime - System.currentTimeMillis());
        }
        return vo;
    }

    @Override
    public WorkerPanel getWorkerPanel() {
        WorkerPanel result = new WorkerPanel();
        WeChatUserCacheVo user = weChatUserHolderUtil.getCurrentUser();
        WorkRecord recentlyWorkerLog = workDao.getRecentlyRecordByRecordUserId(user.getId());
        result.setRecord(recentlyWorkerLog);

        return result;
    }

    @Override
    public Page<WorkRecord> getWorkerRecordList(WorkerRecordQueryDto dto) {
        Page<WorkRecord> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        QueryWrapper<WorkRecord> query = new QueryWrapper<>();
        query.eq("record_user_id", weChatUserHolderUtil.getCurrentUser().getId()).orderByDesc("record_time");
        return workDao.selectPage(page, query);
    }

    @Override
    public int submitRecord(WorkRecord record) {
        Assert.notBlank(record.getTitle(), "标题不能为空");
        Assert.notBlank(record.getContent(), "内容不能为空");
        WeChatUserCacheVo user = weChatUserHolderUtil.getCurrentUser();
        record.setBaseCreateInfo(user.getId());
        return workDao.insert(record);
    }

    @Override
    public PagerEntity<ReplenishmentMachineStockVo> machineStockPager(PagerEntity<ReplenishmentMachineStockVo> pager, ReplenishmentMachineStockQueryDto dto) {
        Assert.notBlank(dto.getMachineId());
        long l = stockDao.countReplenishmentMachineStockVos(dto);
        if (l <= 0) {
            return pager;
        }
        pager.setTotalNum(l);
        List<ReplenishmentMachineStockVo> data = stockDao.listReplenishmentMachineStockVos(pager, dto);
        pager.setData(data);
        if (CollUtil.isEmpty(data)) {
            return pager;
        }
        for (int i = 0; i < data.size(); i++) {
            ReplenishmentMachineStockVo v = data.get(i);
            if (StrUtil.isNotEmpty(v.getCommodityImg())) {
                v.setCommodityImg(imgAccessPathPrefix + v.getCommodityImg());
            }
        }
        return pager;
    }

    @Transactional
    @Override
    public int replenishmentMachineStockData(ReplenishmentStockDataDto dto) {
        List<Integer> ids = Lists.newArrayList(dto.getId());
        List<CommodityMachineStockUpdateDto> list = Lists.newArrayList(new CommodityMachineStockUpdateDto(dto.getId(), dto.getIncreaseCount()));
        int i = stockDao.reduceStockTotalRemainCount(list, ids);
        int i1 = stockDao.reduceStockToBeSoldCount(list,ids);
        return i + i1;
    }

    @Override
    public Page<UserOpinionListItemVo> getUserOpinionPage(UserOpinionQueryDto dto) {
        Page<UserOpinionListItemVo> page = new Page<>();
        WeChatUserCacheVo user = weChatUserHolderUtil.getCurrentUser();
        dto.setUserId(user.getId());
        Integer count = opinionDao.selectCount(new QueryWrapper<SystemOpinion>().eq("record_user_id", user.getId()));
        if (count <= 0) {
            return page;
        }
        List<UserOpinionListItemVo> data = opinionDao.listUserOpinionListItemVos(dto);
        page.setRecords(data);
        page.setTotal(count);
        return page;
    }

    @Override
    public OpinionInfoVo getUserOpinionDetail(String id) {
        OpinionInfoVo opinionInfoVo = opinionDao.getOpinionInfoVo(id);
        return opinionInfoVo;
    }

    @Override
    public int submitOpinion(SystemOpinion opinion) {
        WeChatUserCacheVo user = weChatUserHolderUtil.getCurrentUser();
        opinion.setBaseCreateInfo(user.getId());
        opinion.setAlreadyResponse(ResponseStatus.NOT_RESPONSE.getCode());
        // 不填电话号码直接视作无需联系
        if (StrUtil.isBlank(opinion.getCallBackPhoneNumber())) {
            opinion.setNeedCallBack(CallBackStatus.NOT_NEED.getCode());
            opinion.setCallBackTime(0);
        }
        int i = opinionDao.insert(opinion);
        WebSocketMessageEntity entity = new WebSocketMessageEntity();
        entity.setMessageType(WebSocketServiceType.MESSAGE);
        entity.setTitle("意见反馈");
        entity.setContent("收到一条用户的意见反馈");
        messageService.sendMessageToAll("系统", entity);
        return i;
    }

    private Map<String, String> getWechatPaymentResult(String orderId, String openId, String commodityName, double price, String nonceStr) {
        // 生成统一下单接口需要的xml格式参数
        String requestContent = weChatPayRequestBodyFactory.createRequestContent(openId, commodityName, orderId, price, nonceStr);
        String rs = httpClientUtil.doPost(payUrl, requestContent);
        Assert.notNull(rs, "支付失败");
        // 将微信平台返回的xml格式数据转换成Map集合
        Map<String, String> weChatResult = ConvertUtils.XMLParsing(rs);
        Map<String, String> result = Maps.newHashMap();
        if ("SUCCESS".equals(weChatResult.get("return_code"))) {
            String prepayId = weChatResult.get("prepay_id");
            result.put("nonceStr", nonceStr);
            result.put("package", "prepay_id=" + prepayId);
            //要返回的时间戳需为字符串，否则小程序那边会出现错误
            String timeStamp = String.valueOf(System.currentTimeMillis());
            result.put("timeStamp", timeStamp);
            // 二次签名
            String resultSign = new StringBuilder().append("appId=").append(appId).append("&nonceStr=").append(nonceStr).append("&package=prepay_id=").append(prepayId).append("&signType=MD5&timeStamp=").append(timeStamp).append("&key=").append(mchKey).toString();
            result.put("paySign", DigestUtils.md5Hex(resultSign.getBytes(StandardCharsets.UTF_8)));
        } else {
            log.error(weChatResult.get("return_msg"));
            throw new ServiceException("server error");
        }
        return result;
    }


}
